package com.pcafs.manage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.pcafs.common.utils.SecurityUtils;
import com.pcafs.manage.bo.PcafsFieldAddBo;
import com.pcafs.manage.bo.PcafsFieldEditBo;
import com.pcafs.manage.bo.PcafsFieldQueryBo;
import com.pcafs.manage.domain.PcafsField;
import com.pcafs.manage.mapper.PcafsFieldMapper;
import com.pcafs.manage.service.IPcafsFieldService;
import com.pcafs.manage.vo.PcafsFieldVo;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 字段信息Service业务层处理
 *
 * @author pcafs
 * @date 2022-05-05
 */
@Service
public class PcafsFieldServiceImpl extends ServiceImpl<PcafsFieldMapper, PcafsField> implements IPcafsFieldService {

    @Override
    public PcafsFieldVo queryById(Long id) {
        PcafsField db = this.baseMapper.selectById(id);
        return BeanUtil.toBean(db, PcafsFieldVo.class);
    }

    @Override
    public List<PcafsFieldVo> queryList(PcafsFieldQueryBo bo) {
        LambdaQueryWrapper<PcafsField> lqw = Wrappers.lambdaQuery();
        lqw.like(StrUtil.isNotBlank(bo.getFieldName()), PcafsField::getFieldName, bo.getFieldName());
        lqw.eq(StrUtil.isNotBlank(bo.getFieldType()), PcafsField::getFieldType, bo.getFieldType());
        lqw.eq(bo.getFieldLength() != null, PcafsField::getFieldLength, bo.getFieldLength());
        lqw.eq(StrUtil.isNotBlank(bo.getFieldEn()), PcafsField::getFieldEn, bo.getFieldEn());
        lqw.eq(StrUtil.isNotBlank(bo.getTabNameEn()), PcafsField::getTabNameEn, bo.getTabNameEn());
        return entity2Vo(this.list(lqw));
    }

    @Override
    public List<PcafsField> queryAll(PcafsFieldQueryBo bo) {
        return this.baseMapper.queryAll(bo.getTabNameEn());
    }

    @Override
    public Integer haveData(String tabNameEn) {
        return this.baseMapper.haveData(tabNameEn);
    }

    @Override
    public Map<String, Object> getFieldAndData(String tabNameEn) {
        // 获取字段
        List<PcafsField> pcafsFields = this.baseMapper.queryAll(tabNameEn);
        List<Map> tabData = this.baseMapper.selectTabData(tabNameEn);
        Map<String, Object> map = new HashMap<>(16);

        map.put("filed",pcafsFields);
        map.put("tabData",tabData);
        return map;
    }

    @Override
    public List<Map> getTabData(String tabNameEn) {
        return this.baseMapper.selectTabData(tabNameEn);
    }

    @Override
    public List<PcafsField> getFieldList(String tabNameEn) {
        return this.baseMapper.queryAllField(tabNameEn);
    }

    @Override
    public Map importData(MultipartFile file) throws IOException {
        String name = file.getOriginalFilename();
        List<Map<String, Object>> mapList;
        if (StrUtil.endWith(name,"txt")) {
            mapList =  this.parseTxt(file);
        } else if (StrUtil.endWith(name,"xml")){
            mapList =  this.parseXml(file);
        }else {
            mapList =  this.parseExcel(file);
        }
        HashMap<Object, Object> map = new HashMap<>();
        map.put("tabData",mapList);
        map.put("fields",mapList.get(0).keySet());
        return map;
    }

    @Override
    public String importDataToTab(Map map) {
        String tabNameEn = (String) map.get("tabNameEn");
        if(StrUtil.isBlank(tabNameEn)){
            return "表名为空";
        }
        Integer integer = this.baseMapper.tabExist(tabNameEn);
        if(integer == 0){
            return "表不存在";
        }
        List<Map<String,Object>> tabDatas = (List<Map<String,Object>>) map.get("tabData");
        for (Map<String, Object> tabData : tabDatas) {
            tabData.put("cjr", SecurityUtils.getUserId());
            this.insertTabVal(tabData,tabNameEn);
        }
        return "数据成功插入";
    }

    public void insertTabVal(Map maps, String tableName) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("insert into "+tableName+"(");
        Set set = maps.keySet();
        int i = 0;
        for (Object o : set) {
            i++;
            if (set.size() == i){
                buffer.append(o);
            }else{
                buffer.append(o+",");
            }
        }
        buffer.append(")value(");
        Collection values = maps.values();
        int j =0;
        for (Object value : values) {
            j++;
            if(values.size() == j){
                buffer.append("'"+value+"'");
            }else{
                buffer.append("'"+value+"'"+",");
            }
        }
        buffer.append(")");
        this.baseMapper.insertTabVal(buffer.toString());
    }

    /**
     *
     * @Author hyh
     * @Date 11:05 2022/5/8
     * @param file: 
     **/
    public List<Map<String,Object>> parseExcel(MultipartFile file) throws IOException {
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
        List<Map<String,Object>> readAll = reader.readAll();
        return readAll;

    }
    /**
     *
     * @Author hyh
     * @Date 11:05 2022/5/8
     * @param file: 
     **/
    public List<Map<String,Object>> parseTxt(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        BufferedReader reader = IoUtil.getReader(inputStream, Charset.defaultCharset());
        Object[] array = reader.lines().toArray();
        if(array.length == 0){
            return null;
        }
        String[] fields = array[0].toString().split(" ");
        List<Map<String, Object>> list = new ArrayList<>();
        for (int i = 1; i < array.length; i++) {
            String[] val = array[i].toString().split(" ");
            Map<String, Object> map = new HashMap<>(16);
            for (int j = 0; j < fields.length; j++) {
                map.put(fields[j],val[j]);
            }
            list.add(map);
        }
        return list;
    }
    /**
     *
     * @Author hyh
     * @Date 11:05 2022/5/8
     * @param file: 
     **/
    public List<Map<String,Object>> parseXml(MultipartFile file) throws IOException {
        Document document = XmlUtil.readXML(file.getInputStream());
        String xmlStr = XmlUtil.toStr(document);
        Map<String, Object> map = XmlUtil.xmlToMap(xmlStr);
        Set<String> keySet = map.keySet();
        for (String s : keySet) {
            return  (List<Map<String,Object>>)map.get(s);
        }
        return null;
    }

    /**
     * 实体类转化成视图对象
     *
     * @param collection 实体类集合
     * @return
     */
    private List<PcafsFieldVo> entity2Vo(Collection<PcafsField> collection) {
        List<PcafsFieldVo> voList = collection.stream()
                .map(any -> BeanUtil.toBean(any, PcafsFieldVo.class))
                .collect(Collectors.toList());
        if (collection instanceof Page) {
            Page<PcafsField> page = (Page<PcafsField>) collection;
            Page<PcafsFieldVo> pageVo = new Page<>();
            BeanUtil.copyProperties(page, pageVo);
            pageVo.addAll(voList);
            voList = pageVo;
        }
        return voList;
    }

    @Override
    public Boolean insertByAddBo(PcafsFieldAddBo bo) {
        PcafsField add = BeanUtil.toBean(bo, PcafsField.class);
        validEntityBeforeSave(add);
        this.addTabField(bo);
        return this.save(add);
    }

    /**
     * 表添加字段
     *
     * @param bo:
     * @Author hyh
     * @Date 14:24 2022/5/6
     **/
    public void addTabField(PcafsFieldAddBo bo) {
        String tabNameEn = bo.getTabNameEn();
        Integer fieldLength = bo.getFieldLength();
        Integer fieldDecimalLength = bo.getFieldDecimalLength();
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("ALTER TABLE " + tabNameEn);
        stringBuffer.append(" ADD");
        stringBuffer.append(" " + bo.getFieldEn() + " ");
        stringBuffer.append(" " + bo.getFieldType() + " ");

        if (fieldDecimalLength != null) {
            stringBuffer.append(" ( " + fieldLength + "," + fieldDecimalLength + ") ");
        } else if (fieldLength != null) {
            stringBuffer.append(" ( " + bo.getFieldLength() + " ) ");
        }
        String sql = stringBuffer.toString();
        this.baseMapper.addTabField(sql);
    }

    /**
     * 表修改字段
     *
     * @param bo:
     * @Author hyh
     * @Date 14:24 2022/5/6
     **/
    public void updateTabField(PcafsFieldEditBo bo) {

        PcafsField pcafsField = this.baseMapper.selectById(bo.getId());
        String tabNameEn = bo.getTabNameEn();
        String fieldEn = bo.getFieldEn();
        String fieldType = bo.getFieldType();
        Integer fieldLength = bo.getFieldLength();
        Integer fieldDecimalLength = bo.getFieldDecimalLength();

        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("ALTER TABLE " + tabNameEn);
        String oldFieldEn = pcafsField.getFieldEn();
        // 字段名称修改了
        if (!StrUtil.equals(fieldEn, pcafsField.getFieldEn())) {
            if (StrUtil.equals(fieldType, "double")) {
                stringBuffer.append(" change " + oldFieldEn + " " + fieldEn + fieldType + " (" + fieldLength + "," + fieldDecimalLength + ")");
            } else {
                stringBuffer.append(" change " + oldFieldEn + " " + fieldEn + fieldType + " (" + fieldLength + ")");
            }
        }

        if (!StrUtil.equals(fieldType, pcafsField.getFieldType()) || !fieldLength.equals(pcafsField.getFieldLength())
                || !fieldDecimalLength.equals(pcafsField.getFieldDecimalLength())) {
            if (StrUtil.equals(fieldType, "double")) {
                stringBuffer.append(" modify " + fieldEn + fieldType + " (" + fieldLength + "," + fieldDecimalLength + ")");
            } else {
                stringBuffer.append(" modify " + fieldEn + fieldType + " (" + fieldLength + ")");
            }
        }
        String sql = stringBuffer.toString();
        this.baseMapper.updateTabField(sql);
    }

    public void delTabField(Collection<Integer> ids) {
        for (Integer id : ids) {
            PcafsField pcafsField = this.baseMapper.selectById(id);
            String tabNameEn = pcafsField.getTabNameEn();
            String fieldEn = pcafsField.getFieldEn();
            StringBuffer sb = new StringBuffer();
            sb.append("alter table " + tabNameEn +" drop "+ fieldEn);
            this.baseMapper.delTabField(sb.toString());
        }
    }
    @Override
    public Boolean updateByEditBo(PcafsFieldEditBo bo) {
        PcafsField update = BeanUtil.toBean(bo, PcafsField.class);
        validEntityBeforeSave(update);
        this.updateTabField(bo);
        return this.updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(PcafsField entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Integer> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        this.delTabField(ids);
        return this.removeByIds(ids);
    }
}
